// options.js
// Definition and implementation of Options.

var storage = 
{
	get : (function(item)
	{
		if(!item) //DEBUG
			console.storage("storage.get(undefined)");
		return localStorage.getItem(item);
	}), 

	set : (function(item, newValue, syncable)
	{
		if(!item || newValue == null) //DEBUG
			console.error("storage.set(undefined, undefined)");
		var oldValue = this.get(item);
		localStorage.setItem(item, newValue);
		if(this.useChromeStorage && syncable !== false)
		{
			var items = {};
			items[item] = newValue;
			chrome.storage.sync.set(items);
			//NO notification required after sync.set since we handle
			//chrome.storage.onChanged
		}
		else if(this.onChanged && oldValue != newValue)
			this.onChanged(item, newValue, oldValue);
	}), 

	remove : (function(item, syncable)
	{
		if(!item) //DEBUG
			console.storage("storage.get(undefined)");
		var oldValue = localStorage[item];
		localStorage.removeItem(item);
		if(this.useChromeStorage && syncable !== false)
			chrome.storage.sync.remove(item);
		else if(this.onChanged && oldValue != undefined)
			this.onChanged(item, undefined, oldValue);
	}), 

	canSync : (function()
	{
		return chrome.storage && chrome.storage.sync && 
			chrome.storage.onChanged;
	}), 

	useChromeStorage : false, 
	init : (function()
	{
		//Initialization is necessary only when chrome.storage is used.
		if(!this.canSync())
			return;
		this.useChromeStorage = true;

		//Handling chrome.storage.onChanged to notify setting changes
		//Note that chrome.storage.onChanged will not fire if a `set` 
		//method is called with the same item value as before, which is
		//consistent with the behavior of storage.onChanged.
		//Note that this event will also fire if settings are changed
		//because of sync. That's why we listen for it.
		chrome.storage.onChanged.addListener(function(changes, namespace)
		{
			if(namespace == "sync")
				for(var item in changes)
				{
					//Set items in localStorage so that new valued can be 
					//read
					localStorage.setItem(item, changes[item].newValue);
					this.onChanged && this.onChanged(item, 
						changes[item].newValue, changes[item].oldValue);
				}
		});
	}), 

	_fromBoolean : (function(value, defaultValue)
	{
		if(defaultValue) //defaults to true
			return value != "0" && value != "false";
		else //defaults to false
			return value == "1" || value == "true";
	}), 
	_toBoolean : (function(value, defaultValue)
	{
		if(defaultValue) //defaults to true
			return value ? null : "0";
		else //defaults to false
			return value ? "1" : null;
	}), 

	_fromString : (function(value, defaultValue)
	{
		return value || defaultValue;
	}), 
	_toString : (function(value, defaultValue)
	{
		return value == defaultValue ? null : value;
	}), 

	_fromDefaultEmptyArray : (function(value)
	{
		return value ? JSON.parse(value) : [];
	}), 
	_toDefaultEmptyArray : (function(value)
	{
		return (!value || value.length == 0) ? null : 
			JSON.stringify(value);
	}), 

	_fromInteger : (function(value, defaultValue)
	{
		return value ? parseInt(value) : defaultValue;
	}), 
	_toInteger : (function(value, defaultValue)
	{
		return value == defaultValue ? null : value.toString();
	}), 
};

//=================Properties definition begins===========================
var Options = 
{
/*
 * Domain:
 *     Force ( boolean ) [true] *DEPRECATED*
 *     Current ( string ) ["bbs.stuhome.net"]
 *     Preference ( string ) ["default"|"autoDetect"] {or "alwaysExternal"
                             or "custom"}
 *     PreferredInternalDomain ( string ) ["bbs.stuhome.net"]
 *     PreferredExternalDomain ( string ) ["bbs.qshpan.com"]
 */
Domain: 
{
	_properties: 
	{
		// ****** DEPRECATED ******
		Force:
		{
			storage: "Domain.Force", 
			defaultValue: true, //force single domain by default
			fromStorage: (function(value)
			{
				return storage._fromBoolean(value, this.defaultValue);
			}), 
			toStorage: (function(value)
			{
				return storage._toBoolean(value, this.defaultValue);
			})
		}, 
		Current:
		{
			storage: "Domain.Current", 
			defaultValue: "bbs.stuhome.net", //internal domain by default
			syncable: false, //This option should NOT be synced since 
			//users may use this extension across different types of network
			//environment.
			fromStorage: (function(value)
			{
				return storage._fromString(value, this.defaultValue);
			}), 
			toStorage: (function(value)
			{
				return storage._toString(value, this.defaultValue);
			}), 
		}, 
		Preference:
		{
			storage: "Domain.Preference", 
			fromStorage: (function(value)
			{
				if(value == "default") //"default" has been DEPRECATED
					return "autoDetect";
				else
					return value || "autoDetect";
				//auto detect appropriate domains
			}), 
			toStorage: (function(value)
			{
				return ["alwaysExternal", "custom"].indexOf(value) != -1 ? 
					value : null;
			}), 
		}, 
		PreferredInternalDomain:
		{
			storage: "Domain.PreferredInternalDomain", 
			defaultValue: "bbs.stuhome.net", 
			//default internal domain is bbs.stuhome.net
			fromStorage: (function(value)
			{
				return storage._fromString(value, this.defaultValue);
			}), 
			toStorage: (function(value)
			{
				return storage._toString(value, this.defaultValue);
			}), 
		}, 
		PreferredExternalDomain:
		{
			storage: "Domain.PreferredExternalDomain", 
			defaultValue: "bbs.qshpan.com", 
			//default external domain is bbs.qshpan.com
			fromStorage: (function(value)
			{
				return storage._fromString(value, this.defaultValue);
			}), 
			toStorage: (function(value)
			{
				return storage._toString(value, this.defaultValue);
			}), 
		}, 
	}, 
}, 

/*
 * SignIn:
 *     StaySignedIn ( boolean )
 *     NoWaitAfterSignIn ( boolean )
 */
SignIn:
{
	_properties: 
	{
		StaySignedIn: 
		{
			storage: "SignIn.StaySignedIn", 
			defaultValue: true, //enabled by default
			fromStorage: (function(value)
			{
				return storage._fromBoolean(value, this.defaultValue);
			}), 
			toStorage: (function(value)
			{
				return storage._toBoolean(value, this.defaultValue);
			}), 
		}, 
		NoWaitAfterSignIn:
		{
			storage: "SignIn.NoWaitAfterSignIn", 
			defaultValue: true, //enabled by default
			fromStorage: (function(value)
			{
				return storage._fromBoolean(value, this.defaultValue);
			}), 
			toStorage: (function(value)
			{
				return storage._toBoolean(value, this.defaultValue);
			}), 
		}, 
	}, 
}, 

/*
 * UI:
 *     HideHotlist2 ( boolean )
 *     HideAuthorsInHotList ( boolean ) *LABS*
 *     SimpleRead ( boolean )
 *     HomepageUpdateInterval ( integer ) *LABS*
 *     ShowIP ( boolean ) *LABS*
 *     ReplyAndAt ( boolean ) *LABS* *TEMP*
 */
UI:
{
	_properties:
	{
		HideHotlist2: 
		{
			storage: "UI.HideHotlist2", 
			defaultValue: false, //don't modify UI by default
			fromStorage: (function(value)
			{
				return storage._fromBoolean(value, this.defaultValue);
			}), 
			toStorage: (function(value)
			{
				return storage._toBoolean(value, this.defaultValue);
			}), 
		}, 
		HideAuthorsInHotlist:
		{
			storage: "UI.HideAuthorsInHotlist", 
			defaultValue: false, //don't modify UI by default
			fromStorage: (function(value)
			{
				return storage._fromBoolean(value, this.defaultValue);
			}), 
			toStorage: (function(value)
			{
				return storage._toBoolean(value, this.defaultValue);
			}), 
		}, 
		SimpleRead:
		{
			storage: "UI.SimpleRead", 
			defaultValue: false, //don't modify UI by default
			fromStorage: (function(value)
			{
				return storage._fromBoolean(value, this.defaultValue);
			}), 
			toStorage: (function(value)
			{
				return storage._toBoolean(value, this.defaultValue);
			}), 
		}, 
		HomepageUpdateInterval:
		{
			storage: "UI.HomepageUpdateInterval", 
			defaultValue: 0, 
			fromStorage: (function(value)
			{
				return storage._fromInteger(value, this.defaultValue);
			}), 
			toStorage: (function(value)
			{
				return storage._toInteger(value, this.defaultValue);
			}), 
		}, 
		ShowIP:
		{
			storage: "UI.ShowIP", 
			defaultValue: false, 
			fromStorage: (function(value)
			{
				return storage._fromBoolean(value, this.defaultValue);
			}), 
			toStorage: (function(value)
			{
				return storage._toBoolean(value, this.defaultValue);
			}), 
		}, 
		ReplyAndAt:
		{
			storage: "UI.ReplyAndAt", 
			defaultValue: false, //don't enable until the user is aware
			fromStorage: (function(value)
			{
				return storage._fromBoolean(value, this.defaultValue);
			}), 
			toStorage: (function(value)
			{
				return storage._toBoolean(value, this.defaultValue);
			}), 
		}, 
	
	}, 
}, 

/*
 * Blocking:
 *     PostsByUsers ( array of string )
 *     SignaturesOfUsers ( array of string )
 *     PhotosOfUsers ( array of string )
 *     ImagesInPostsByUsers ( array of string )
 *     PostsFromForums ( array of string )
 */
Blocking:
{
	_properties: 
	{
		PostsByUsers: 
		{
			storage: "Blocking.PostsByUsers", 
			fromStorage: (function(value)
			{
				return storage._fromDefaultEmptyArray(value);
				//block nothing by default
			}), 
			toStorage: (function(value)
			{
				return storage._toDefaultEmptyArray(value);
			}), 
		}, 
		SignaturesOfUsers: 
		{
			storage: "Blocking.SignaturesOfUsers", 
			fromStorage: (function(value)
			{
				return storage._fromDefaultEmptyArray(value);
				//block nothing by default
			}), 
			toStorage: (function(value)
			{
				return storage._toDefaultEmptyArray(value);
			}), 
		}, 
		PhotosOfUsers: 
		{
			storage: "Blocking.PhotosOfUsers", 
			fromStorage: (function(value)
			{
				return storage._fromDefaultEmptyArray(value);
				//block nothing by default
			}), 
			toStorage: (function(value)
			{
				return storage._toDefaultEmptyArray(value);
			}), 
		}, 
		ImagesInPostsByUsers: 
		{
			storage: "Blocking.ImagesInPostsByUsers", 
			fromStorage: (function(value)
			{
				return storage._fromDefaultEmptyArray(value);
				//block nothing by default
			}), 
			toStorage: (function(value)
			{
				return storage._toDefaultEmptyArray(value);
			}), 
		}, 
		PostsFromForums:
		{
			storage: "Blocking.PostsFromForums", 
			fromStorage: (function(value)
			{
				return storage._fromDefaultEmptyArray(value);
				//block nothing by default
			}), 
			toStorage: (function(value)
			{
				return storage._toDefaultEmptyArray(value);
			}), 
		}, 
	}, 
},

/*
 * Notifications:
 *     UpdateUnreadMessageInterval ( integer )
 *     NewMessageNotification ( boolean )
 */
Notifications:
{
	_properties:
	{
		UpdateUnreadMessageInterval:
		{
			storage: "Notifications.UpdateUnreadMessageInterval", 
			defaultValue: 60, 
			fromStorage: (function(value)
			{
				return storage._fromInteger(value, this.defaultValue);
			}), 
			toStorage: (function(value)
			{
				return storage._toInteger(value, this.defaultValue);
			}), 
		}, 
		NewMessageNotification:
		{
			storage: "Notifications.NewMessageNotification", 
			defaultValue: false, 
			fromStorage: (function(value)
			{
				return storage._fromBoolean(value, this.defaultValue);
			}), 
			toStorage: (function(value)
			{
				return storage._toBoolean(value, this.defaultValue);
			}), 
		}, 
	}, 
}, 

/*
 * Subscriptions
 *     RepliesToPosts ( array of object )
 *         url ( string ) //relative URL
 *         title ( string )
 *         lastPost ( string )
 *         updateInterval ( integer ) ***NOT IMPLEMENTED***
 */
Subscriptions: 
{
	_properties:
	{
		RepliesToPosts: 
		{
			storage: "Subscriptions.RepliesToPosts", 
			fromStorage: (function(value)
			{
				return storage._fromDefaultEmptyArray(value);
			}), 
			toStorage: (function(value)
			{
				return storage._toDefaultEmptyArray(value);
			}), 
		}
	}, 
}, 

};
//=================Properties definition ends=============================

storage.init();

(function()
{

function defineProperty(target, name)
{
	Object.defineProperty(target, name, 
	{
		get: (function()
		{
			return target._getProperty(name);
		}), 
		set: (function(newValue)
		{
			target._setProperty(name, newValue);
		}), 
	});
}

for(var cur in Options)
{
	var opt = Options[cur];
	opt._getProperty = (function(name)
	{
		var p = this._properties[name];
		if(p)
			return p.fromStorage(storage.get(p.storage));
	}); 
	opt._setProperty = (function(name, newValue)
	{
		var p = this._properties[name];
		if(p)
		{
			var storageValue = p.toStorage(newValue);
			if(storageValue == null)
				storage.remove(p.storage, p.syncable);
			else
				storage.set(p.storage, p.toStorage(newValue), 
					p.syncable);
		}
	}); 
	for(var name in opt._properties)
		defineProperty(opt, name);
}

//Notifications of setting changes
storage.onChanged = Options.onStorageChanged = (function(item, newValue)
{
	if(item == Options.Domain._properties.Preference.storage || 
		item == Options.Domain._properties.Current.storage)
		Options.Domain.onChanged && Options.Domain.onChanged(
			item == Options.Domain._properties.Preference.storage ? 
			"Preference" : "Current", newValue);
	else if(item == Options.SignIn._properties.StaySignedIn.storage)
		Options.SignIn.onChanged && Options.SignIn.onChanged();
	else if(item == Options.Notifications._properties.
		UpdateUnreadMessageInterval.storage)
		Options.Notifications.onChanged && 
		Options.Notifications.onChanged();
});


})();

function onOptionsMessage(message, sender, sendResponse)
{
	var response = {};
	if(message.optionNames)
	{
		if(message.optionNames.indexOf("Blocking.PostsByUsers") != -1)
			response.PostsByUsers = Options.Blocking.PostsByUsers;
		if(message.optionNames.indexOf("Blocking.SignaturesOfUsers") 
			!= -1)
			response.SignaturesOfUsers = Options.Blocking.SignaturesOfUsers;
		if(message.optionNames.indexOf("Blocking.PhotosOfUsers") != -1)
			response.PhotosOfUsers = Options.Blocking.PhotosOfUsers;
		if(message.optionNames.indexOf(
			"Blocking.ImagesInPostsByUsers") != -1)
			response.ImagesInPostsByUsers = 
				Options.Blocking.ImagesInPostsByUsers;
		if(message.optionNames.indexOf("Blocking.PostsFromForums") != -1)
			response.PostsFromForums = Options.Blocking.PostsFromForums;
		if(message.optionNames.indexOf("SignIn.NoWaitAfterSignIn") != -1)
			response.NoWaitAfterSignIn = Options.SignIn.NoWaitAfterSignIn;
		if(message.optionNames.indexOf("UI.HideHotlist2") != -1)
			response.HideHotlist2 = Options.UI.HideHotlist2;
		if(message.optionNames.indexOf("UI.HideAuthorsInHotlist") != -1)
			response.HideAuthorsInHotlist = Options.UI.HideAuthorsInHotlist;
		if(message.optionNames.indexOf("UI.SimpleRead") != -1)
			response.SimpleRead = Options.UI.SimpleRead;
		if(message.optionNames.indexOf("UI.HomepageUpdateInterval") != -1)
			response.HomepageUpdateInterval = Options.UI.HomepageUpdateInterval;
		if(message.optionNames.indexOf("UI.ShowIP") != -1)
			response.ShowIP = Options.UI.ShowIP;
		if(message.optionNames.indexOf("UI.ReplyAndAt") != -1)
			response.ReplyAndAt = Options.UI.ReplyAndAt;
	}
	sendResponse(response);
}

